package com.yc.framework.interceptor;

import com.alibaba.fastjson2.JSON;
import com.yc.common.core.domain.AjaxResult;
import com.yc.common.core.redis.RedisCache;
import com.yc.common.utils.WebUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

/**
 * 令牌验证拦截器，用于限制令牌验证的频率并防止令牌爆破攻击
 * @Author YanChen
 * @Date 2025/4/13 12:40
 **/
@Component
public class TokenValidateInterceptor implements HandlerInterceptor {

    private static final Logger log = LoggerFactory.getLogger(TokenValidateInterceptor.class);

    private static final String TOKEN_VALIDATE_FREQUENCY_KEY = "token:validate:freq:";
    private static final int MAX_VALIDATE_FREQUENCY = 10; // 1分钟内最多请求10次

    @Autowired
    private RedisCache redisCache;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String uri = request.getRequestURI();

        // 仅对令牌验证接口进行限制
        if (uri.contains("/token/validate")) {
            String ipAddress = WebUtil.getIpAddr();
            String key = TOKEN_VALIDATE_FREQUENCY_KEY + ipAddress;

            // 获取当前访问次数
            Integer count = redisCache.getCacheObject(key);
            if (count == null) {
                // 首次访问，设置计数为1
                redisCache.setCacheObject(key, 1, 1L, TimeUnit.MINUTES);
                return true;
            }

            // 判断是否超过限制
            if (count >= MAX_VALIDATE_FREQUENCY) {
                log.warn("IP: {} 验证令牌请求过于频繁: {}/{} 次/分钟", ipAddress, count, MAX_VALIDATE_FREQUENCY);
                responseError(response, "验证请求过于频繁，请稍后再试");
                return false;
            }

            // 增加计数
            redisCache.setCacheObject(key, count + 1, 1L, TimeUnit.MINUTES);
        }

        return true;
    }

    private void responseError(HttpServletResponse response, String message) throws IOException {
        response.setContentType("application/json;charset=UTF-8");
        response.setStatus(429); // Too Many Requests

        AjaxResult result = AjaxResult.error(429, message);
        response.getWriter().write(JSON.toJSONString(result));
    }
}
